package hc.bre.flow

import hc.bre.ComponentRegistry
import hc.bre.cmn.RuleScriptBuilder
import hc.bre.cmn.RuleDefinition
import hc.bre.cmn.struct.DataStruct
import hc.bre.cmn.struct.DataStructItem


@groovy.transform.CompileStatic
class FlowBuilder extends RuleScriptBuilder<FlowDefinition>{
	@Override
	public void buildClassRuleBodyCore() {

		apdNl("Map<Integer,Map> _stateMachine_ =[");
		nested{
			ruleDef.nodeList.each{ FlowNodeItem flowNode ->
				apdNl("${flowNode.id}:[itemType:'${flowNode.itemType}',");
				nested{
					buildStateAction(flowNode);
					buildTransition(flowNode);
				}

				apdNl("],");
			};
		};
		apdNl("];");

		int startState = ruleDef.nodeList.find({
			it.itemType=='start'
		}).id;

		String loop =
				"""
def _node_ = _stateMachine_[${startState}];//the start node
while(_node_.itemType != 'end')
{
	if(_node_.itemType in ['task','start'])
	{
		_node_.action();
		_node_ = _stateMachine_[_node_.nextStateId];
	}
	else if(_node_.itemType == 'switch')
	{
		_node_ = _stateMachine_[_node_.nextStateId[_node_.action().clas.id]];
	}
	else assert false;
}
""";

		apdNlBlock(loop);

		apdNl("${result}.rets = [:];")
		this.ruleDef.retList.each {
			def variRef = this.referVariable(it.referId);
			def dot = variRef.lastIndexOf('.')
			def variToken = dot>=0? variRef.substring(dot+1):variRef;
			apdNl("${result}.rets.${variToken} = ${variRef};")
		}
	};

	void buildStateAction(FlowNodeItem flowNode) {
		if(flowNode.itemType in ['start', 'end']) {
			apdNl("action:{},");
			return;
		}else {
			apdNl("action:{");
			nested{
				apdNl("def ${rresult} = ${referApplyRule(flowNode.referId)};")

				DataStruct resultStruct = this.resultStruct(flowNode.referId);
				flowNode.resultMap.each {  dataId, varId ->
					if(!varId) return;
					String var = ruleOfVariable.accessRouteOf(varId);
					String data = resultStruct.accessRouteOf(dataId);
					apdNl("${var} = ${data};");
				}

				apdNl("return ${rresult};")
			}
			apdNl("},");
		}
	};

	void buildTransition(FlowNodeItem flowNode) {
		List<FlowLineItem> finded = ruleDef.lineList.findAll(){
			it.sourceId == flowNode.id
		};

		switch(flowNode.itemType) {
			case 'start':
			case 'task':
				apdNl("nextStateId:${finded[0].targetId},");
				break;
			case 'switch':
				apdNl("nextStateId:[");
				nested{
					finded.each	{
						apdNl("${it.referId}:${it.targetId},")
					}
				}
				apdNl('],');

				break;
			case 'end':
				apdNl("nextStateId:0,");
				break;
		}
	}
}
